﻿namespace TrinityEngine
{
    public struct Vector2Int : IEquatable<Vector2Int>
    {
        public int x;

        public int y;

        public float sqrMagnitude
        {
            get
            {
                return x * x + y * y;
            }
        }

        public float magnitude
        {
            get
            {
                return Mathf.Sqrt(sqrMagnitude);
            }
        }

        public Vector2Int(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public readonly static Vector2Int zero = new Vector2Int(0, 0);

        public readonly static Vector2Int one = new Vector2Int(1, 1);

        public readonly static Vector2Int up = new Vector2Int(0, 1);

        public readonly static Vector2Int down = new Vector2Int(0, -1);

        public readonly static Vector2Int left = new Vector2Int(-1, 0);

        public readonly static Vector2Int right = new Vector2Int(1, 0);

        public Vector3Int ToVector3Int(int z = 0)
        {
            return new Vector3Int(x, y, z);
        }

        public static Vector2Int operator -(Vector2Int a)
        {
            return new Vector2Int(-a.x, -a.y);
        }

        public static Vector2Int operator +(Vector2Int a, Vector2Int b)
        {
            return new Vector2Int(a.x + b.x, a.y + b.y);
        }

        public static Vector2Int operator -(Vector2Int a, Vector2Int b)
        {
            return new Vector2Int(a.x - b.x, a.y - b.y);
        }

        public static Vector2Int operator *(Vector2Int a, Vector2Int b)
        {
            return new Vector2Int(a.x * b.x, a.y * b.y);
        }

        public static Vector2Int operator *(Vector2Int a, int b)
        {
            return new Vector2Int(a.x * b, a.y * b);
        }

        public static Vector2Int operator *(int a, Vector2Int b)
        {
            return b * a;
        }

        public static Vector2 operator *(Vector2Int a, float b)
        {
            return new Vector2(a.x * b, a.y * b);
        }

        public static Vector2 operator *(float a, Vector2Int b)
        {
            return b * a;
        }

        public static Vector2Int operator /(Vector2Int a, Vector2Int b)
        {
            if (b.x * b.y == 0)
            {
                throw new Exception("Dividend could not be zero!");
            }

            return new Vector2Int(a.x / b.x, a.y / b.y);
        }

        public static Vector2Int operator /(Vector2Int a, int b)
        {
            if (b == 0)
            {
                throw new Exception("Dividend could not be zero!");
            }

            return new Vector2Int(a.x / b, a.y / b);
        }

        public static Vector2Int operator /(int a, Vector2Int b)
        {
            return b / a;
        }

        public bool Equals(Vector2Int other)
        {
            return x == other.x && y == other.y;
        }

        public override bool Equals(object obj)
        {
            if (obj is Vector2Int v)
            {
                return Equals(v);
            }

            return false;
        }

        public override int GetHashCode()
        {
            return x.GetHashCode() ^ y.GetHashCode();
        }

        public override string ToString()
        {
            return $"Vector2Int({x}, {y})";
        }

        public static bool operator ==(Vector2Int a, Vector2Int b)
        {
            return a.Equals(b);
        }

        public static bool operator !=(Vector2Int a, Vector2Int b)
        {
            return !a.Equals(b);
        }

        public static implicit operator OpenTK.Mathematics.Vector2i(Vector2Int a)
        {
            return new OpenTK.Mathematics.Vector2i(a.x, a.y);
        }
    }
}
